using System;
using System.ComponentModel;

using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

[assembly: WebResource("SBPweb.Controls.Web.Resources.countdown.js", "text/javascript")]
namespace SBPweb.Controls.Web
{

	/// <summary>
	/// Desiner support for the CountDownTimer class
	/// </summary>
	public class DesignerCountDownTimer : ControlDesigner
	{

		/// <summary>
		/// Renders the Desing-Time html of the CountDownTimer class
		/// </summary>
		/// <returns></returns>
		public override string GetDesignTimeHtml()
		{
			return String.Format("<span>CountDown Timer({0})</span>", (Component as CountDownTimer).InitialTime.ToString());
		}

	}

	/// <summary>
	/// This class be used as a client-side (Javascript based) countown timer. When the countdown reaches 0,
	/// there are two options: redirect to a page, or postback the form on which the Control is.
	/// </summary>
	[Designer(typeof(DesignerCountDownTimer))]
	[ToolboxData("<{0}:CountDownTimer runat=server></{0}:CountDownTimer>")]
	[Description("Client-side (Javasrcipt based) countwon timer")]
	public class CountDownTimer : WebControl
	{
		/// <summary>
		/// Defines the two available behavior modes
		/// </summary>
		public enum ActionMode
		{
			/// <summary>
			/// At the end of the countdown the page will be redirected (RedirectURL must be set)
			/// </summary>
			Redirect, 

			/// <summary>
			/// At the end of the countdown the from will be posted back
			/// </summary>
			PostBack,

			/// <summary>
			/// At the end of the countdown the specified javascript function will be called
			/// </summary>
			Javascript
		}


		#region Public Properties

		/// <summary>
		/// Gets or sets that the countwon should be started after the page is loaded by the browser
		/// </summary>
		[Bindable(true)]
		[Category("Behavior")]
		[DefaultValue(true)]
		[Description("Gets or sets that the countwon should be started after the page is loaded by the browser")]
		public bool ActivateAtLoad
		{
			get
			{
				if (ViewState["ActivateAtLoad"] == null)
				{
					ViewState["ActivateAtLoad"] = true;
				}
				return (bool)ViewState["ActivateAtLoad"];
			}

			set
			{
				ViewState["ActivateAtLoad"] = value;
			}
		}

		/// <summary>
		/// Gets or sets the behavior mode at the end of the countdown
		/// </summary>
		[Bindable(true)]
		[ListBindable(true)]
		[Category("Behavior")]
		[DefaultValue(typeof(SBPweb.Controls.Web.CountDownTimer.ActionMode), "Redirect")]
		[Description("Gets or sets the behavior mode at the end of the countdown")]
		public ActionMode ActionAtZero
		{
			get
			{
				if (ViewState["ActionAtZero"] == null)
				{
					ViewState["ActionAtZero"] = ActionMode.Redirect;
				}
				return (ActionMode)ViewState["ActionAtZero"];
			}
			set
			{
				ViewState["ActionAtZero"] = value;
			}
		}

		/// <summary>
		/// Gets or sets the Redirection url (only used if ActionAtZero is set to Redirect mode)
		/// </summary>
		[Bindable(true)]
		[Category("Data")]
		[Localizable(true)]
		[UrlProperty()]
		[Description("Gets or sets the Redirection url (only used if ActionAtZero is set to Redirect mode)")]
		public string RedirectUrl
		{
			get
			{
				String s = (String)ViewState["RedirectUrl"];
				if (s == null)
				{
					if (!DesignMode)
					{
						s = Page.Request.Url.OriginalString;
					}
					else
					{
						s = string.Empty;
					}
					ViewState["RedirectUrl"] = s;
				}
				return s;
			}

			set
			{
				ViewState["RedirectUrl"] = value;
			}
		}

		/// <summary>
		/// Gets or sets the Javascript function to be called at the end of the countdown
		/// </summary>
		[Bindable(true)]
		[Category("Behavior")]
		[Description("Gets or sets the Javascript function to be called at the end of the countdown")]
		public string JavascriptFunction
		{
			get
			{
				String s = (String)ViewState["JavascriptFunction"];
				return ((s == null) ? String.Empty : s);
			}
			set
			{
				ViewState["JavascriptFunction"] = value;
			}
		}
			 

		/// <summary>
		/// Gets or sets the initial time of the Timer
		/// </summary>
		[Bindable(true)]
		[Category("Data")]
		[Localizable(true)]
		[Description("Gets or sets the initial time of the Timer")]
		public TimeSpan InitialTime
		{
			get
			{
				if (ViewState["InitialTime"] == null)
				{
					ViewState["InitialTime"] = new TimeSpan(0,1,0);
				}
				return (TimeSpan)ViewState["InitialTime"];
			}

			set
			{
				ViewState["InitialTime"] = value;
			}
		}

		/// <summary>
		/// Gets or sets the warning time of the Timer. If the timer reaches the time defined, the CssClass
		/// of the Control is replaced to the WarningCssClass
		/// </summary>
		[Bindable(true)]
		[Category("Data")]
		[Localizable(true)]
		[Description(@"Gets or sets the warning time of the Timer. If the timer reaches the time defined, 
					   the CssClass of the Control is replaced to the WarningCssClass")]
		public TimeSpan WarningTime
		{
			get
			{
				if (ViewState["WarningTime"] == null)
				{
					ViewState["WarningTime"] = new TimeSpan(0, 0, 10);
				}
				return (TimeSpan)ViewState["WarningTime"];
			}

			set
			{
				ViewState["WarningTime"] = value;
			}
		}

		/// <summary>
		/// Gets or sets the warning CssClass of the Timer. If the timer reaches the time defined, the CssClass
		/// of the Control is replaced to the WarningCssClass
		/// </summary>
		[Bindable(true)]
		[Category("Appearance")]
		[Description(@"Gets or sets the warning CssClass of the Timer. If the timer reaches the time defined, the CssClass
					   of the Control is replaced to the WarningCssClass")]
		public string WarningCssClass
		{
			get
			{
				String s = (String)ViewState["WarningCssClass"];
				return ((s == null) ? String.Empty : s);
			}
			set
			{
				ViewState["WarningCssClass"] = value;
			}
		}

		#endregion


		#region Overrided Methods

		/// <summary>
		/// Render the controls, and register the necessary sript resources
		/// </summary>
		/// <param name="e"></param>
		protected override void OnPreRender(EventArgs e)
		{
			HtmlGenericControl span = new HtmlGenericControl("span");
			span.Attributes.Add("class", CssClass);
			Controls.Add(span);

			// add static js library (can be cached by browsers)
			Page.ClientScript.RegisterClientScriptInclude
			(
				"countdownJS",
				Page.ClientScript.GetWebResourceUrl
				(
					this.GetType(), "SBPweb.Controls.Web.Resources.countdown.js"
				)
			);

			// add dynamic js library
			string js = "function onTimerZero(){{{0}}}";
			if (ActionAtZero == ActionMode.Redirect)
			{
				js = String.Format(js, "document.location='" + RedirectUrl + "';");
			}
			else if(ActionAtZero == ActionMode.PostBack)
			{
				js = String.Format(js, "document.forms[0].submit();");
			}
			else if (ActionAtZero == ActionMode.Javascript)
			{
				js = String.Format(js, JavascriptFunction);
			}

			HtmlGenericControl script = new HtmlGenericControl("script");
			script.Attributes.Add("type", "text/javascript");
			script.Attributes.Add("language", "javascript");
			script.InnerHtml = String.Format
			(
				"{0}InitCountDown('{1}', {2}, {3}, '{4}', onTimerZero);",
				js, span.ClientID, ((int)InitialTime.TotalSeconds).ToString(),
				((int)WarningTime.TotalSeconds).ToString(), WarningCssClass
			);
			if (ActivateAtLoad)
			{
				script.InnerHtml += "window.setTimeout('CountDownTick()', 1000)";
			}
			Controls.Add(script);

			base.OnPreRender(e);
		}

		#endregion


		#region Public Methods

		/// <summary>
		/// Gets the parametrized Javascript function call to place in a script block to 
		/// reactivate the CountDownTimer at any time
		/// </summary>
		/// <param name="initialTime">Starting time</param>
		/// <param name="warningTime">Time when warning mode activated</param>
		/// <returns></returns>
		public string GetCountdownReactivateScript(TimeSpan initialTime, TimeSpan warningTime)
		{
			return String.Format
			(
				"ReactivateCountdown({0},{1},'{2}');",
				((int)initialTime.TotalSeconds).ToString(),
				((int)warningTime.TotalSeconds).ToString(),
				CssClass
			);
		}

		/// <summary>
		/// Gets the parametrized Javascript function call to place in a script block to stop the timer.
		/// </summary>
		/// <returns>the javascript code snipplet</returns>
		public string GetCountDownStopScript()
		{
			return "SetEnabled(false);";
		}

		/// <summary>
		/// Gets the parametrized Javascript function call to place in a script block to start the timer.
		/// </summary>
		/// <returns>the javascript code snipplet</returns>
		public string GetCountDownStartScript()
		{
			return "SetEnabled(true);window.setTimeout('CountDownTick()', 1000);";
		}

		#endregion


		#region Private methods

		/// <summary>
		/// Helper method find a control Recursively stating from the Control given by a parameter
		/// </summary>
		/// <param name="id"></param>
		/// <param name="ct"></param>
		/// <returns></returns>
		private Control FindControlRecursively(string id, Control ct)
		{
			if (ct == null)
			{
				return null;
			}

			if (ct.ID == id)
			{
				return ct;
			}
			else
			{
				if (ct.HasControls())
				{
					Control c;
					foreach (Control ctl in ct.Controls)
					{
						if ((c = FindControlRecursively(id, ctl)) != null)
							return c;
					}
				}
				return null;
			}
		}

		#endregion

	}
}
